package com.masu.knows.sys.interceptor;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.WebAuthenticationDetails;
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
import java.util.Map;

/**
 * @author susi
 * @date 2022/5/18
 */
@Component
public class AuthInterceptor implements HandlerInterceptor {

    @Autowired
    private RestTemplate restTemplate;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //我们要获得用户发送过来的Jwt
        // 拦截器中获得用户请求中的信息代码如下
        String token=request.getParameter("accessToken");
        // 利用auth授权服务器的功能,完成解析jwt的工作
        String url="http://auth-service/oauth/check_token?token={1}";
        Map<String,Object> map=restTemplate.getForObject(
                url, Map.class,token);
        // 根据我们观察的返回结果,我们需要的数据是
        // 获得当前登录用户的用户名: map.get("user_name")
        // 获得当前用户所有权限和角色的: map.get("authorities")
        // 因为因为权限和角色是一个数组,在现在的情况下被解析为一个List接收
        String username=map.get("user_name").toString();
        List<String> list=(List<String>)map.get("authorities");
        //获得了用户必要的信息,下面要将这些信息保存到Spring-Security中
        // 而要通过编码方式保存,需要遵守固定格式
        String[] auth=list.toArray(new String[0]);
        UserDetails userDetails= User.builder()
                .username(username)
                .password("")
                .authorities(auth)
                .build();
        // 上面代码获得了一个UserDetails类型对象
        // 我们要将它保存到Spring-Security框架中,
        //  以便@AuthenticationPrincipal注解获得
        //  Spring-Security框架给了固定方式实现这个目标
        PreAuthenticatedAuthenticationToken authenticationToken=
                new PreAuthenticatedAuthenticationToken(
                        userDetails,userDetails.getPassword(),
                        AuthorityUtils.createAuthorityList(auth)
                );
        // 由于我们是要将这个用户保存到Spring-Security,所以需要关联当前请求
        authenticationToken.setDetails(
                new WebAuthenticationDetails(request)
        );
        // 将当前保存用户信息的对象添加到Spring-Security中
        SecurityContextHolder.getContext()
                .setAuthentication(authenticationToken);
        // 千万别忘了将返回值改为true!!!!!
        return true;
    }
}
